from flask import request, jsonify, current_app, make_response, session
from info.utils.response_code import RET
from info.utils.captcha.captcha import captcha
from info import reg_redis, constants, db
import re
from info.models import User
import random
from info.libs.yuntongxun import sms
from . import register_blu


# 1.图片验证码
@register_blu.route('/image_code')
def generate_image_code():
    # 获取图片参数--使用请求查询参数的方式
    image_code_id = request.args.get('image_id')
    # 判断参数不存在
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数不存在')
    # 调用扩展生成图片验证码
    name, text, image = captcha.generate_captcha()
    print(text)
    # 将图片验证码内容存储进redis中
    try:
        reg_redis.setex('imageId-' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        # 使用应用上下文保存异常信息
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='数据异常')
    else:
        # 使用响应对象来返回图片，目的是修改响应的数据类型以使表里如一，即数据与实际数据类型一致
        response = make_response(image)
        response.headers['Content-Type'] = 'image/jpg'
        return response


# 2.发送短信验证码
@register_blu.route('/sms_code', methods=['POST'])
def send_sms_code():
    """
    发送短信
     1、获取参数，mobile,image_code,image_code_id
     2、判断参数的完整性
     3、验证手机号格式，正则
     4、校验图片验证码，从redis读取真实的图片验证码
     real_image_code = redis._store.get(key)
     5、判断获取结果是否存在，如果不存在，表示已过期
     6、如果图片验证码存在，需要删除图片验证码，本质是任意一个图片验证码，只能读取一次；
     7、比较图片验证码内容是否一致；
     8、查询mysql数据库，确认手机号是否已经注册；
     9、生成短信随机数；六位
     10、把短信随机数保存到redis数据库中，设置有效期
     11、调用云通讯扩展，来发送短信，保存发送结果
     12、判断发送结果是否成功。
    :return:
    """
    # 1.获取参数 手机号/验证码内容/验证码编号uuid
    mobile = request.json.get('mobile')
    image_code = request.json.get('image_code')
    image_code_id = request.json.get('image_code_id')
    print(image_code)

    # 2.判断参数完整性
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')

    # 3.验证手机号格式
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式不正确')

    # 4.校验图片验证码，从redis中读取真实的校验码
    try:
        real_image_code = reg_redis.get('imageId-' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.NODATA, errmsg='获取图片验证码失败')

    # 判断验证码是否存在，不存在则代表已过期
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg='图片验证码已过期')

    # 5.如果验证码存在，则删除图片验证码
    try:
        reg_redis.delete('imageId-' + image_code_id)
    except Exception as e:
        # 如果删除异常，则可以不用return，因其会自然过期
        current_app.logger.error(e)

    # 6.比较图片验证码是否一致,不区分大小写
    if real_image_code.lower() != image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg='图片验证码不一致')

    # 7.查询数据库 判断手机号是否已注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='查询用户信息失败')
    else:
        if user is not None:
            return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')

    # 8.生成短信验证码，随机数，六位
    sms_code = '%06d' % random.randint(0, 999999)

    # 9.将短信验证码存到redis数据库中
    try:
        reg_redis.setex('SMSCode_' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='短信验证码保存失败')

    # 10.调用第三方：云通讯发送短信并判断短信是否发送成功
    try:
        result = sms.CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='短信发送异常')

    # 11.判断短信发送是否成功
    if result == 0:
        return jsonify(errno=RET.OK, errmsg='短信发送成功')
    else:
        return jsonify(errno=RET.THIRDERR, errmsg='短信发送失败')


# 3.用户注册部分
@register_blu.route('/register', methods=['POST'])
def register():
    # 1.获取用户参数
    mobile = request.json.get('mobile')
    smscode = request.json.get('smscode')
    password = request.json.get('password')

    # 2.判断参数是否完整
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')

    # 3.判断手机号格式是否正确
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号码格式错误')

    # 4.比较短信验证码
    # 4.1.从redis中获取短信验证码
    try:
        real_smscode = reg_redis.get('SMSCode_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='获取验证码失败')
    # 4.2.判断获取的验证码数据是否有结果
    if not real_smscode:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期')
    # 4.3.对用户输入的验证码和真实验证码进行对比
    if smscode != real_smscode:
        return jsonify(errno=RET.DATAERR, errmsg='验证码不正确，请重新输入')
    # 4.4.验证码匹配成功后，删除redis中的验证码
    try:
        reg_redis.delete('SMSCode_' + mobile)
    except Exception as e:
        current_app.logger.error(e)

    # 5.验证密码长度是否不小于6位
    if len(password) < 6:
        return jsonify(errno=RET.DATAERR, errmsg='密码长度应不小于6位')

    # 6.判断手机号是否已注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='手机号查询异常')
    # 6.1.判断查询的结果是否有数据,判断手机号是否已注册
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg='此手机号已注册')

    # 7.将用户信息存储进数据库中：实例化模型类
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    # 7.1.对密码进行加密
    user.password = password
    # 7.2.将数据保存进数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DATAERR, errmsg='用户信息保存失败')

    # 8.将用户信息缓存进redis中
    session['user_id'] = user.id
    session['mobile'] = mobile
    session['nick_name'] = mobile
    session['is_admin'] = user.is_admin

    # 9.注册成功后返回结果
    return jsonify(errno=RET.OK, errmsg='OK')


# 4.用户登录部分
@register_blu.route('/login', methods=['POST'])
def login():
    # 1.获取登陆信息:mobile/password
    mobile = request.json.get('mobile')
    password = request.json.get('password')

    # 2.判断参数是否完整
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')

    # 3.判断手机号码格式
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号码格式错误')

    # 4.根据手机号查询数据库获取用户信息
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='用户信息查询失败')
    # 4.1.判断用户名是否存在
    # if not user:
    #     return jsonify(errno=RET.USERERR, errmsg='用户名不存在')
    # 4.2.判断密码是否正确
    # if not User.check_password(password):
    #     return jsonify(errno=RET.PWDERR, errmsg='密码错误')

    # 4.3.判断用户名或密码是否正确
    if not user or not user.check_password(password):
        return jsonify(errno=RET.LOGINERR, errmsg='用户名或密码错误')

    # 5.用户登陆信息正确，缓存用户信息到redis中
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    session['is_admin'] = user.is_admin

    # 6.返回登录结果
    return jsonify(errno=RET.OK, errmsg='OK')


# 5.用户退出部分
@register_blu.route('/logout')
def logout():
    # 1.退出的本质：清除redis中缓存的用户信息
    session.pop('user_id')
    session.pop('mobile')
    session.pop('nick_name')
    session.pop('is_admin', None)
    return jsonify(errno=RET.OK, errmsg='OK')
